NDK无法找到动态链接库;动态链接库找不到依赖的gcc库;JNI中无法找到要注册的类;and so on

您所在的位置:网站首页 Android ndk动态库依赖动态库 NDK无法找到动态链接库;动态链接库找不到依赖的gcc库;JNI中无法找到要注册的类;and so on

NDK无法找到动态链接库;动态链接库找不到依赖的gcc库;JNI中无法找到要注册的类;and so on

2023-11-02 22:10| 来源: 网络整理| 查看: 265

这是一篇头一次做NDK开发,记录了踩坑,杂乱无章的错误记录,仅供参考.

待解决Android运行NDK程序无法加载库,无法找到库,缺失库文件,找不到c库,导致我的Android NDK程序直接崩溃退出,,经过一番侦查发现,通过file获知,我们使用的gcc编译,搞错了编译工具链,使用arm工具链编译,OK,这个问题解决,然后由弹出找不到libgcc_s.so.1,好嘛,C库缺失,很显然,我拷贝一个C库过去就好了

首先从之前制作好的最小根文件系统中提取出libgcc_s.so.1这个库文件,然后使用ADB,

ADB shell 将文件推入 adb push ./libgcc_s.so.1 /system/lib/ `` 这里,它提示我们这是只读文件系统

A:\Users\defenion\Desktop\ARM练习\FASTBOOT>adb push ./libgcc_s.so.1 /system/lib/ failed to copy './libgcc_s.so.1' to '/system/lib//libgcc_s.so.1': Read-only file system

我们通过重新挂载解决它

1|root@android:/ # mount -o remount,rw /dev/null /system [ 1499.316842] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)

Ok 看样子是挂载成功

然后重新将我们从linux根文件系统中提取出来的C库push进去

A:\Users\defenion\Desktop\ARM练习\FASTBOOT>adb push ./libgcc_s.so.1 /system/lib/ 6792 KB/s (69371 bytes in 0.009s)

然后再次启动我们的Android APP,在Android Studio 的ADB信息中看到 错误依旧

Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1936]: 1295 could not load needed library 'libgcc_s.so.1' for 'libhardcontrol.so' (link_image[1936]: 1295 could not load needed library 'libc.so.6' for 'libgcc_s.so.1' (load_library[1091]: Library 'libc.so.6' not found))

注意,这句是重点,是因为libc.so.6导致我们不能加载刚才导入的libgcc_s.so.1库文件,

could not load needed library 'libc.so.6' for 'libgcc_s.so.1'

看来还需要将 libc.so.6 导入 ,显然啊 ,这是C系的库都没有包含,,,,并且shell中还有很多常用的sh命令被删除了, 待解决~ ! 搁置 20200106 20:18 目前看来最简单的解决办法是将Linux最小根文件系统中的C库全部copy进来 这个也很是诡异,之前使用eclipse从未出现过这种问题,使用Android Studio.就遇见了缺少依赖的动态链接库.暂不探究. 对比下他们的文件信息

#他们同为ARM交叉编译工具链编译出来的 root@ubuntu:/mnt/hgfs/ubuntu# file *.so #之前使用eclipse时使用的NDK库,没有任何问题 libled.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, stripped #这次出问题的NDK库,使用Android Studio libnative.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, not stripped

有区别,( ′◔ ‸◔`),,我们再次找到了线索

探究 stripped与not stripped ,以及将Linux最小根文件系统中的C库全部copy进来这个方法.

正常版本是通过NDK编译工具链编译出来的,出错的版本是通过GCC手动指定参数进行编译的

NDK编译工具链 root@ubuntu:/usr/local/ndk/android-ndk-r8b# vim ndk-build这东西是一个脚本,本质上依然是调用ARM-GCC进行的交叉编译.

关于stripped与not stripped

用file命令查看文件信息的时候,显示如下: libcom_err.so.2: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped

libcrypto.so.10: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped

libcrypt.so.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped

libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped

libdl.so.2: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped 第一个最后显示的是stripped,第二个是not stripped。而且对于同样名字的动态库,带not stripped库会大很多。

参考elf文件格式与动态链接库博客 a.out和elf(Executable and Linking Format)。这两种格式中都有符号表(symbol table),其中包括所有的符号(程序的入口点还有变量的地址等等)。在elf格式中符号表的内容会比a.out格式的丰富的多。但是这些符号表可以用 strip工具去除,这样的话这个文件就无法让debug程序跟踪了,但是会生成比较小的可执行文件。a.out文件中的符号表可以被完全去除,但是 elf中的在加载运行时起着重要的作用,所以用strip永远不可能完全去除elf格式文件中的符号表。但是用strip命令不是完全安全的,比如对未连接的目标文件来说如果用strip去掉符号表的话,会导致连接器无法连接。

回过头来,我们接着尝试解决刚才提到的问题

尝试1

既然使用NDK编译工具链编译成功了,那我们也使用一下这个编译工具链,康康是否可行 参考以前的NDK笔记

需要编译的文件,在目录“ledtest\jni”中 –Android.mk(编译脚本) –com_topeet_ledtest_led.c –com_topeet_ledtest_led.h •拷贝文件夹“jni”到Ubuntu系统,,,,(JNI文件夹为 调用底层驱动的接口) 进入jni目录执行 ndk-build编译 •编译完成后,在Ubuntu目录“../” -->“libs”-->“armeabi”中生成库文件“libled.so”,该文件就是安卓应用程序中需要的“.so”文件。 •将该文件拷贝到工程ledtest的“\libs\armeabi”目录下,库文件的编译就全部完成了。

注:这个NDK编译工具链是Android文件系统中自带的工具之一. 我们需要先建立Android.mk文件 在我们拷贝的jni文件中建立一个Andoird.mk文件 ,输入如下内容

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hardcontrol LOCAL_SRC_FILES := native.c LOCAL_LDLIBS += -llog LOCAL_LDLIBS +=-lm include $(BUILD_SHARED_LIBRARY)

第三行是编译出来的文件的名称libxxxx.so,第四行是我们源文件名称 编译,

root@ubuntu:~/yizhi/jni# ndk-build Compile thumb : hardcontrol libs/armeabi/libhardcontrol.so

生成在上层libs目录中,../libs/armeabi/libhardcontrol.so 放入我们的工程中,然后用前面的方法push到android的system/lib目录下,我们在测试

libhardcontrol.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped

这回这个和以前未出过依赖gcc库问题的库文件一样了都是剥离了符号表的stripped类型 测试! 在虚拟机上跑一下,不出所料,程序依旧崩溃退出.但是显然我们解决了这个问题,错误信息中没有提示找不到我们加载的库文件 报错信息:

Caused by: java.lang.NoClassDefFoundError: HardControl Caused by: java.lang.ClassNotFoundException: HardControl

显然,我们的库文件成功的加载了,但是没有找到我们在C文件中指定注册的类.

使用其他的NDK库加载成功,可能是JAVA类和C指定的某些地方不匹配,暂定

static { Log.d("AAA","AAAAAAAAA"); System.loadLibrary("adc"); }

使用其他的NDK测试成功,成功,成功的原因是这个C库中没有尝试使用 cls = (*env)->FindClass(env, "HardControl");这句代码

暂定 20200107 21:09

在自用的安卓手机,Android 7上测试 ,提示出了稍有区别的错误,但是本质上是一样的问题,都是找不到类

01-08 13:45:05.447 29811-29811/? A/DEBUG: Abort message: 'art/runtime/java_vm_ext.cc:470] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn't find class "HardControl" on path: DexPathList[[zip file "/data/app/com.example.ratherdog.app_addons_0001_message-1/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ratherdog.app_addons_0001_message-1/lib/arm, /system/fake-libs, /data/app/com.example.ratherdog.app_addons_0001_message-1/base.apk!/lib/armeabi, /system/lib, /vendor/

试了直接指定其他类也不行,加上包名,OKay,可以找到我们需要的类HardControl了 JNI注册类是这么写就OK

jclass cls = (*env)->FindClass(env, "com/thisway/hardlibrary/HardControl");

一定要指定包名 , 接下来,继续报错

java.lang.NoSuchMethodError: no static or non-static method "Lcom/thisway/hardlibrary/HardControl;.` ledCtrl(I)I`"

错误的地点

public class HardControl{ public static native int ledCtrl(int which,int status); public static native int ledOpen(); public static native void ledClose(); //加载hardcontrol这个名字的C库,这种静态写法是加载C库的标准写法,因为static内的代码只能被执行一次,并且在类创建实例的时候最先执行 //static方法只执行一次,最先执行,适合用于加载库, static { try { System.loadLibrary("hardcontrol"); } catch (Exception e) { e.printStackTrace(); } } }

找不到这样的方法是把ledCtrl(I)I

static const JNINativeMethod methods[] = { {"ledOpen", "()I", (void *)ledOpen}, {"ledClose", "()V", (void *)ledClose}, {"ledCtrl", "(I)I", (void *)ledCtrl}, };

显然这里面写的不匹配. {"ledCtrl", "(I)I", (void *)ledCtrl},这里一个参数,java中两个参数 改为

{"ledCtrl", "(II)I", (void *)ledCtrl},

测试 在KindleFire HD 10中测试,Android4.4.4,通过,在虚拟机中测试通过,在魅蓝Note6,Andoird中测试通过,

完美解决 !



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3